<?php

/**
 * This file is part of the Codizer package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @copyright   Copyright (c) 2010 Advisa (http://www.advisa.fr)
 * @author      Codizer Core Team <team@codizer.org>
 * @package     Codizer
 */

class f_loader_Config
{
	private static $instance;
	
	private $directory = CONFIG_DIR;
	private $suffix;
	private $file;
    private $parameters;

	/**
	 * Constructor
	 */
	public function __construct()
	{
        if(!is_dir(CONFIG_DIR))
        {
            throw new Exception('CONFIG_DIR does not exists');
        }
        
        $this->suffix = self::getSuffixFromUserProfile();
        $this->file = realpath($this->directory.DS."config.".$this->suffix.".ini");

        if(!is_file($this->file))
        {
            if (php_sapi_name() == 'cli')
            {
                $this->shellCreate();
            }
            else
            {               
                $this->suffix = 'prod';
                $this->file = realpath($this->directory.DS."config.".$this->suffix.".ini");

                if(!is_file($this->file))
                {
                     trigger_error("Config file webapp/config/config.".$this->suffix.".ini does not exist", E_USER_ERROR);
                }
            }
        }

        $this->parameters = $this->getParameters();
		return $this;
	}

	/**
	 * @return f_loader_Config
	 */
	public static function getInstance()
	{
		if(is_null(self::$instance))
		{
			self::$instance = new self();
		}
		return self::$instance;
	}

    public static function getSuffixFromUserProfile()
    {
        try
		{
            $file = BASE_DIR.DS."..".DS."userProfile";

            $bd = explode(':', ini_get("open_basedir"));

            if((count($bd) == 0) || (!in_array(BASE_DIR, $bd) && file_exists($file)))
            {
                $suffix = trim(file_get_contents(realpath($file)));

                if($suffix != "")
                {
                    return $suffix;
                }
                else
                {
                    return "prod";
                }
            }
            else
            {
                return "prod";
            }
        }
		catch(Exception $e)
		{
			return "prod";
		}
    }

    /**
     * Get current used config suffix
     * @return string
     */
    public function getConfigSuffix()
    {
        return $this->suffix;
    }

    /**
     * Get the current config file path
     * @return string
     */
    public function getConfigFilePath()
    {
        return $this->file;
    }

    public function setParameter($section, $key, $value)
    {
        $this->parameters[$section][$key] = $value;
        return $this;
    }

    public function getParameter($section, $key, $default = null)
    {
        if(isset($this->parameters[$section][$key]))
        {
            return $this->parameters[$section][$key];
        }
        return $default;
    }

    /**
     * Writes parameters in current ini file
     * @param array $array
     * @param <type> $file 
     */
    public function save()
    {
        $res = array();
        foreach($this->parameters as $section => $parameter)
        {
            $res[] = '['.$section.']';

            foreach($parameter as $key => $val)
            {
                if(is_array($val))
                {
                    $res[] = "[$key]";
                    foreach($val as $skey => $sval)
                    {
                        $res[] = "$skey = ".(is_numeric($sval) ? $sval : '"'.$sval.'"');
                    }
                }
                else
                {
                    $res[] = "$key = ".(is_numeric($val) ? $val : '"'.$val.'"');
                }
            }
        }

        return $this->writeIniFile(implode("\r\n", $res));
    }

    private function writeIniFile($datas)
    {
        $fPath = $this->getConfigFilePath();

        if(is_file($fPath))
        {
            if ($fp = fopen($fPath, 'w'))
            {
                $startTime = microtime();
                do
                {
                    $canWrite = flock($fp, LOCK_EX);
                    if(!$canWrite)
                    {
                        usleep(round(rand(0, 100)*1000));
                    }
                }
                while ((!$canWrite)and((microtime()-$startTime) < 1000));

                //file was locked so now we can store information
                if ($canWrite)
                {
                    fwrite($fp, $datas);
                    flock($fp, LOCK_UN);
                }
                fclose($fp);
            }
            return true;
        }
        return false;
    }

	/**
	 * Get parameters from ini file
	 *
	 * @param string $section
	 * @return array
	 */
	public function getParameters($section = null)
	{
        if(is_null($this->file)) return null;

		try
		{
			if(is_null($section))
			{
				return parse_ini_file($this->file, true);
			}
			else
			{
				$iniFileParameters = parse_ini_file($this->file, true);
				return $iniFileParameters[$section];
			}
		}
		catch(Exception $e)
		{
			throw new Exception($e);
		}
	}
	
	/**
	 * Create a new contextual config file in shell if not exist 
	 */
	private function shellCreate()
	{
		if(CLI_MODE)
		{
            $this->suffix = self::getSuffixFromUserProfile();
			echo COLOR_RED."ERROR -> ".COLOR_NORMAL."It seems that you don't have a config file for your profile (".$this->suffix.")\n";
			fwrite(STDOUT, COLOR_GREEN."Confirm".COLOR_NORMAL." -> Create a config file for your profile (y/n)\n");
			$test = trim(fgets(STDIN));
			
			if($test != "n" && $test != "y")
			{
				$this->shellCreate();
			}
			
			if($test == "n")
			{
				die();
			}
			else
			{
				$sourceFile = FRAMEWORK_HOME.DS."builder".DS."defaultdocuments".DS."config.example.ini";
				$destFile = CONFIG_DIR.DS."config.".$this->suffix.".ini";
				if(copy($sourceFile, $destFile))
				{
					echo COLOR_GREEN."WRITING -> ".COLOR_NORMAL."File config.".$this->suffix.".ini created\n";
                    $this->file = $destFile;
                    $this->parameters = $this->getParameters();
				}
				else
				{
					echo COLOR_RED."ERROR -> ".COLOR_NORMAL."Cannot create config.".$this->suffix.".ini file\n";
				}
				return $this;
			}
		}
        else
        {
            throw new Exception('You are not allowed to perform this action in http mode');
        }
	}
}